package com.appkubes.fintech.admin.application.signature.fadada.service.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.appkubes.fintech.admin.application.bill.dao.RentBillHeaderDao;
import com.appkubes.fintech.admin.application.bill.enums.RentBillEnums;
import com.appkubes.fintech.admin.application.order.dao.RentOrderDao;
import com.appkubes.fintech.admin.application.signature.fadada.service.FadadaSignService;
import com.appkubes.fintech.admin.application.user.dao.UserBaseInfoDao;
import com.appkubes.fintech.admin.application.user.dao.UserPersonalDao;
import com.appkubes.fintech.admin.util.MyOkHttpUtil;
import com.appkubes.fintech.common.exption.BusinessException;
import com.appkubes.fintech.common.plan.BillInfoVo;
import com.appkubes.fintech.common.plan.BillPlaneUtile;
import com.appkubes.fintech.common.response.Response;
import com.appkubes.fintech.core.po.*;
import com.fadada.sdk.client.FddClientBase;
import com.fadada.sdk.client.FddClientExtra;
import com.fadada.sdk.client.authForplatform.ApplyClientNumCert;
import com.fadada.sdk.client.authForplatform.PersonDeposit;
import com.fadada.sdk.client.authForplatform.model.*;
import com.fadada.sdk.client.request.ExtsignReq;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Author: leeming
 * @Date: 2020-01-10 19:18
 * @Description:
 */
@Service
@Slf4j
public class FadadaSignServiceImpl implements FadadaSignService {
    private static String V = "2.0";

    @Value("${fadada.data.appId}")
    private String appId;

    @Value("${fadada.data.apiUrl}")
    private String apiUrl;

    @Value("${fadada.data.customerId}")
    private String company_customerId;

    @Value("${fadada.data.appSecret}")
    private String appSecret;

    @Value("${fadada.data.templateId}")
    private String templateId;

    @Value("${fadada.data.company_name}")
    private String company_name;
    @Value("${fadada.data.company_address}")
    private String company_address;
    @Value("${fadada.data.company_phone}")
    private String company_phone;

    @Resource
    private UserBaseInfoDao userBaseInfoDao;

    @Resource
    private UserPersonalDao userPersonalDao;

    @Resource
    private RentOrderDao rentOrderDao;
    @Resource
    private RentBillHeaderDao headerDao;
    @Override
    public Response signAuto(String orderKey) {
        try {
            FintechRentOrder order = rentOrderDao.selectByPrimaryKey(orderKey);
            if (order == null) {
                return com.appkubes.fintech.common.response.Response.fail("订单信息错误");
            }
            if (order.getContractUrl()!=null && !order.getContractUrl().equals("")) {
                //"该订单已经签章过，无需重复签章"
                log.info("该订单已经签章过，无需重复签章");
                return com.appkubes.fintech.common.response.Response.success(order.getContractUrl());
            }
            String userKey = order.getUserKey();
            FintechUserBaseInfo baseInfo = userBaseInfoDao.selectByPrimaryKey(userKey);
            FintechUserPersonal userPersonal =  userPersonalDao.selectByPrimaryKey(userKey);
            if (userPersonal == null || baseInfo == null) {
                return com.appkubes.fintech.common.response.Response.fail("用户信息错误");
            }

            Random random = new Random();
            String contractId = userKey+random.nextInt(10000);
            //uploadTemplate();
            String customer_id = regAccount(baseInfo);
            String evidence_no = PersonDeposit(baseInfo,userPersonal,customer_id);
            ApplyClientNumCert(customer_id,evidence_no);
            customSignature(customer_id,baseInfo);
            GenerateContract(contractId,baseInfo,order);
            String allUrl = extsignAuto(customer_id,baseInfo,contractId,orderKey);
            System.out.println("signAuto-orderKey: " + orderKey);
            log.info("signAuto-orderKey: {}",orderKey);
            return com.appkubes.fintech.common.response.Response.success(allUrl);
        } catch (Exception e) {
            log.error("合同签署异常",e);
            return com.appkubes.fintech.common.response.Response.fail("合同签署异常");
        }
    }

    @Override
    public Response getContractUrl(String orderKey) {
        try {
            FintechRentOrder order = rentOrderDao.selectByPrimaryKey(orderKey);
            if (order == null) {
                return com.appkubes.fintech.common.response.Response.fail("订单信息错误");
            }
            return com.appkubes.fintech.common.response.Response.success(order.getContractUrl());
        } catch (Exception e) {
            return com.appkubes.fintech.common.response.Response.fail("获取合同出错s");
        }
    }


    /***
     * 1,注册账号
     * @param baseInfo
     * @return
     */
    public String regAccount(FintechUserBaseInfo baseInfo){
        FddClientBase base = new FddClientBase(appId,appSecret,V,apiUrl);
        String open_id = baseInfo.getUserKey();
        String account_type = "1";
        String result =base.invokeregisterAccount(open_id,account_type);
        System.out.println("regAccount result:" + result);
        JSONObject resJson = JSONObject.parseObject(result);
        if (resJson.getString("code").equals("1")) {
            return resJson.getString("data");
        }
        throw new BusinessException("签章用户注册错误");
    }

    /***
     * 2,个人存证
     * @param baseInfo
     * @param userPersonal
     */
    public String PersonDeposit(FintechUserBaseInfo baseInfo,FintechUserPersonal userPersonal,String customer_id){
        PersonDeposit personDeposit = new PersonDeposit(appId,appSecret,V,apiUrl);
        PersonDepositReq req = new PersonDepositReq();
        req.setCustomer_id(customer_id); //客户编号

        req.setPreservation_name(baseInfo.getRealName() + "存证"); //存证名称
        //req.setPreservation_desc(""); //存证描述
        req.setPreservation_data_provider("存证数据提供方");//存证数据提供方

        req.setName(baseInfo.getRealName());//姓名
        req.setDocument_type("0");//证件类型 默认是0：身份证
        req.setIdcard(baseInfo.getIdentityNum());//证件号
        req.setMobile(baseInfo.getPhone());//手机号
        req.setVerified_type("2");//实名存证类型

        MobileEssentialFactor mobile_essential_factor = new MobileEssentialFactor();
        //2:手机三要素(姓名+身份证+手机号);
        mobile_essential_factor.setTransactionId("123");
        req.setMobile_essential_factor(mobile_essential_factor);//verified_type =2手机三要素

        String result = personDeposit.invokePersonDeposit(req);
        JSONObject resJson = JSONObject.parseObject(result);
        if (resJson.getString("code").equals("1")) {
            return resJson.getString("data");
        }
        throw new BusinessException("签章个人存证错误");
    }


    /***
     * 3,编号证书申请，获取ca证书
     * @param customer_id
     * @param evidence_no
     */
    public void ApplyClientNumCert(String customer_id,String evidence_no){
        ApplyClientNumCert applyClientNumCert = new ApplyClientNumCert(appId,appSecret,V,apiUrl);
        String result = applyClientNumCert.invokeapplyClinetNumcert(customer_id,evidence_no);
        JSONObject resJson = JSONObject.parseObject(result);
        if (!resJson.getString("code").equals("1")) {
            throw new BusinessException("编号证书申请错误");
        }
    }

    /***
     * 4,自定义印章
     * @param customer_id
     */
    public void customSignature(String customer_id,FintechUserBaseInfo baseInfo){
        FddClientBase base = new FddClientBase(appId,appSecret,V,apiUrl);
        String content = baseInfo.getRealName();
        String result = base.invokecustomSignature(customer_id,content);
        JSONObject resJson = JSONObject.parseObject(result);
        if (!resJson.getString("code").equals("1")) {
            throw new BusinessException("编号证书申请错误");
        }

        base = new FddClientBase(appId,appSecret,V,apiUrl);
        result = base.invokecustomSignature(company_customerId,company_name);
        resJson = JSONObject.parseObject(result);
        if (!resJson.getString("code").equals("1")) {
            throw new BusinessException("编号证书申请错误");
        }
    }

    /***
     * 5,自动签署   不雅问我为什么，第三方就是这样蛋疼，不能传递多个关键字，每个盖章的地方都要重新签章一边
     * @param customerId
     * @param baseInfo
     * @param contractId
     * @param orderKey
     * @return
     * @throws Exception
     */
    public String extsignAuto(String customerId,FintechUserBaseInfo baseInfo,String contractId,String orderKey ) throws Exception{
        String transactionId = contractId;
        //用户签章
        FddClientBase base = new FddClientBase(appId,appSecret,V,apiUrl);
        ExtsignReq req = new ExtsignReq();
        req.setCustomer_id(customerId);
        req.setTransaction_id(transactionId + "_01");
        req.setContract_id(contractId);
        req.setClient_role("1");
        req.setSign_keyword("乙方：");
        req.setKeyword_strategy("2");
        req.setDoc_title(baseInfo.getRealName() + "租赁合同");
        String result = base.invokeExtSignAuto(req);

        //企业签章
        base = new FddClientBase(appId,appSecret,V,apiUrl);
        req = new ExtsignReq();
        req.setCustomer_id(company_customerId);
        req.setTransaction_id(transactionId + "_02");
        req.setContract_id(contractId);
        req.setClient_role("1");
        req.setSign_keyword("乙方：");
        req.setKeyword_strategy("2");
        req.setDoc_title(baseInfo.getRealName() + "租赁合同");
        result = base.invokeExtSignAuto(req);

        //用户签章
        base = new FddClientBase(appId,appSecret,V,apiUrl);
        req = new ExtsignReq();
        req.setCustomer_id(customerId);
        req.setTransaction_id(transactionId + "_03");
        req.setContract_id(contractId);
        req.setClient_role("1");
        req.setSign_keyword("授权人（签字）");
        req.setDoc_title(baseInfo.getRealName() + "租赁合同");
        result = base.invokeExtSignAuto(req);

        //用户签章
        base = new FddClientBase(appId,appSecret,V,apiUrl);
        req = new ExtsignReq();
        req.setCustomer_id(customerId);
        req.setTransaction_id(transactionId + "_04");
        req.setContract_id(contractId);
        req.setClient_role("1");
        req.setSign_keyword("授权人签章：");
        req.setDoc_title(baseInfo.getRealName() + "租赁合同");
        result = base.invokeExtSignAuto(req);

        //企业签章
        base = new FddClientBase(appId,appSecret,V,apiUrl);
        req = new ExtsignReq();
        req.setCustomer_id(company_customerId);
        req.setTransaction_id(transactionId + "_05");
        req.setContract_id(contractId);
        req.setClient_role("1");
        req.setSign_keyword("被授权人（盖章）");
        req.setDoc_title(baseInfo.getRealName() + "租赁合同");
        result = base.invokeExtSignAuto(req);

        //用户签章
        base = new FddClientBase(appId,appSecret,V,apiUrl);
        req = new ExtsignReq();
        req.setCustomer_id(customerId);
        req.setTransaction_id(transactionId + "_06");
        req.setContract_id(contractId);
        req.setClient_role("1");
        req.setSign_keyword("授权人（签字）：");
        req.setDoc_title(baseInfo.getRealName() + "租赁合同");
        result = base.invokeExtSignAuto(req);
        JSONObject resJson = JSONObject.parseObject(result);
        if (!resJson.getString("code").equals("1000")) {
            throw new BusinessException("签章错误");
        }
        String download_url = resJson.getString("download_url");
        String viewpdf_url = resJson.getString("viewpdf_url");

        String allUrl = download_url + "|" + viewpdf_url;
        rentOrderDao.updateOrderContractUrl(allUrl,orderKey);
        return allUrl;
    }

    /***
     * 模板填充
     */
    public void GenerateContract(String contractId,FintechUserBaseInfo baseInfo,FintechRentOrder order) throws IOException {
        FddClientBase base = new FddClientBase(appId,appSecret,V,apiUrl);
        Calendar calendar = Calendar.getInstance();
        int curYear = calendar.get(Calendar.YEAR);
        int curMonth = calendar.get(Calendar.MONTH) +1;
        int curDay = calendar.get(Calendar.DATE);

        SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd");
        String font_size = "11";
        String font_type = "";
        JSONObject paramter = new JSONObject();

        BillInfoVo billInfoVo = BillPlaneUtile.planBill(order.getPeriodType(), order.getPeriods()
                , order.getPeriodDays(), order.getRentAmount()/100,order.getInterestRate()); //按照元计算
        FintechRentBillHeader header = saveBillHeader(order, billInfoVo);

        JSONObject goodsDetail = getGoodsAttrAndAssociate(order.getOrderKey());
        System.out.println("getGoodsAttrAndAssociate-" + order.getOrderKey()+":" + goodsDetail.toJSONString());

        //第一页
        paramter.put("fill_1",company_name);
        paramter.put("fill_2",company_address);
        paramter.put("fill_3",company_phone);
        paramter.put("fill_4",baseInfo.getRealName());
        paramter.put("fill_5",baseInfo.getIdentityNum());
        paramter.put("fill_6",baseInfo.getPhone());
        paramter.put("fill_7",company_name);
        //订单编号
        int total = (header.getBillAmount()+header.getBillInterest())/100;
        double pre = new BigDecimal((double)total/order.getPeriods()).setScale(2, BigDecimal.ROUND_UP).doubleValue();
        paramter.put("fill_8",order.getRentOrderNo());
        paramter.put("fill_9",order.getGoodsTitle() + "(" + getMemoryAttr(goodsDetail.getJSONObject("data").getString("attr")) + ")");                   //设备型号
        paramter.put("fill_10",order.getPeriodDays());                   //服务期限
        paramter.put("fill_11",order.getPeriods());                     //服务期数
        paramter.put("fill_12",pre);                             //每期费用
        paramter.put("fill_13","0");                                    //意外保障费用
        paramter.put("fill_14","0");                             //押金总额
        paramter.put("fill_15",ft.format(order.getRentStartDate()));    //租赁起始日期
        paramter.put("fill_16", DateUtil.format(header.getRentEndDate(),"yyyy-MM-dd") );  //租赁结束日期
        Long peroidDays=DateUtil.between(header.getRentStartDate(),header.getRentEndDate(), DateUnit.DAY);

        paramter.put("fill_17",peroidDays/header.getPeriods());                             //还款周期
        paramter.put("fill_18",pre);                             //每期还款

        //第2页
        paramter.put("fill_1_2",order.getGoodsTitle());
        paramter.put("fill_2_2","官方");

        //第4页
        paramter.put("fill_1_3",company_name);
        paramter.put("fill_2_3",baseInfo.getRealName());
        paramter.put("fill_3_2",curYear + "-" + curMonth + "-" + curDay);

        //第5页
        paramter.put("fill_1_4",company_name);
        paramter.put("fill_2_4",baseInfo.getRealName());
        paramter.put("fill_3_3",baseInfo.getIdentityNum());
        paramter.put("fill_4_2",curYear);
        paramter.put("fill_5_2",curMonth);
        paramter.put("fill_6_2",curDay);

        //第6页
        paramter.put("fill_1_5",baseInfo.getRealName());
        paramter.put("fill_2_5",company_name);
        paramter.put("fill_4_3",curYear);
        paramter.put("fill_3_4",curMonth);
        paramter.put("fill_5_3",curDay);
        paramter.put("fill_6_3",curYear);
        paramter.put("fill_7_2",curMonth);
        paramter.put("fill_8_2",curDay);
        //协议结束期 年月日
        Calendar calendarEnd = Calendar.getInstance();
        calendarEnd.setTime(header.getRentEndDate());
        paramter.put("fill_9_2",calendarEnd.get(Calendar.YEAR));              //协议结束期 年月日
        paramter.put("fill_10_2",calendarEnd.get(Calendar.MONTH) +1);               //协议结束期 年月日
        paramter.put("fill_11_2",calendarEnd.get(Calendar.DATE));               //协议结束期 年月日
        paramter.put("fill_14_2",curYear);
        paramter.put("fill_12_2",curMonth);
        paramter.put("fill_13_2",curDay);

        //第8页
        paramter.put("userName",baseInfo.getRealName());
        paramter.put("userIdNum","身份证" + baseInfo.getIdentityNum());
        paramter.put("fill_1_6",curYear);
        paramter.put("fill_2_6",curMonth);
        paramter.put("fill_3_5",curDay);
        System.out.println("GenerateContract-" + order.getRentOrderKey()+",parameter:" + paramter.toJSONString());
        String result = base.invokeGenerateContract(templateId, contractId, "", font_size, font_type, paramter.toString(), "".toString());
        JSONObject resJson = JSONObject.parseObject(result);
        if (!resJson.getString("code").equals("1000")) {
            log.error("模板填充错误："+result);
            throw new BusinessException("模板填充错误");
        }
        //String viewpdf_url = JSON.parseObject(result).getString("viewpdf_url");
    }

    private  String getMemoryAttr(String attr){
        if(attr.indexOf("GB") == -1){
            return "";
        }
        String[] arr =  attr.split(" ");
        for(String str : arr){
            if(str.indexOf("GB") != -1){
                return str;
            }
        }
        return "";
    }

    @Value("${mall.data.adminHostUrl}")
    private String mallAdminUrl;

    private JSONObject getGoodsAttrAndAssociate(String orderKey) throws IOException {
        if(!mallAdminUrl.endsWith("/")){
            mallAdminUrl += "/";
        }
        okhttp3.Response result = MyOkHttpUtil.get(mallAdminUrl + "order/getGoodsAttrAndAssociate/" + orderKey,new HashMap<>());
        return JSONObject.parseObject(result.body().string());
    }

    /***
     * 0，模板上传
     */
    @Override
    public void uploadTemplate() {
        FddClientBase base = new FddClientBase(appId,appSecret,V,apiUrl);
        File file = new File("/data/template20200520.pdf");
        String result = base.invokeUploadTemplate(templateId, file, "");
        System.out.println("uploadTemplate result:" + result);
        JSONObject resJson = JSONObject.parseObject(result);
        if (!resJson.getString("code").equals("1")) {
            throw new BusinessException("模板上传失败");
        }
    }

    //从RentBillServiceImpl引用过来的
    private FintechRentBillHeader saveBillHeader(FintechRentOrder order, BillInfoVo billInfoVo) {
        FintechRentBillHeader billHeader = new FintechRentBillHeader();
        BeanUtils.copyProperties(order, billHeader);
        billHeader.setOrderKey(order.getRentOrderKey());
        billHeader.setBreaksAmount(0);
        billHeader.setBillFine(0);
        billHeader.setBillAmount(order.getRentAmount()); //租售基恩
        billHeader.setBillInterest(billInfoVo.getInterestAmt() * 100);
        billHeader.setInterestRate(order.getInterestRate());
        billHeader.setSurpInterestAmount(billInfoVo.getInterestAmt() * 100);
        billHeader.setRepayInterest(0);
        billHeader.setBillNo("B" + DateUtil.format(new Date(), "yyMMddHHmmss") + RandomUtil.randomNumbers(3));
        billHeader.setPeriods(order.getPeriods());
        billHeader.setPeriodsDays(order.getPeriodDays());
        billHeader.setPeriodsType(order.getPeriodType());
        billHeader.setBillKey(UUID.randomUUID().toString().replaceAll("-", ""));
        billHeader.setCreateTime(new Date());
        billHeader.setSurpFineAmount(0);
        billHeader.setRepayAmount(0);
        billHeader.setUnpayAmount(billInfoVo.getDetailVoList().get(0).getPayAmt() * 100);
        billHeader.setUnpayPeriods(1);
        billHeader.setUnpayDate(DateUtil.parse(billInfoVo.getDetailVoList().get(0).getEndDate(), "yyyy-MM-dd"));
        billHeader.setSurpAmount(billHeader.getBillAmount());
        billHeader.setUnpayFineAmount(0);
        billHeader.setStatus(RentBillEnums.还款中.getValue());
        billHeader.setRentEndDate(DateUtil.parse(billInfoVo.getEndDate(), "yyyy-MM-dd"));
        billHeader.setRentStartDate(DateUtil.parse(billInfoVo.getStartDate(), "yyyy-MM-dd"));
        billHeader.setUnpayInterestAmount(billInfoVo.getDetailVoList().get(0).getPayInterestAmt() * 100);
        billHeader.setRepayFineAmount(0);
        billHeader.setRepayChangeAmount(0);// 多余的零头钱
//        billHeader.setFineRate(fineRate.divide(new BigDecimal(100)));
//        billHeaderMapper.insert(billHeader);
        return billHeader;
    }
}
